/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dp1.pucp.Modelo.Algoritmos;

import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author Rodrigo
 */
public class Recocido {
//    
//    private double tInicial = 100;//Temperatura Inicial
//    private double tMinima = 0.5;//Temperatura Final
//    private double ratioEnfriamiento=0.004;//Ratio de enfriamiento de la temperatura
//    private float alfaRecocido=1.0f;//alfa del grasp construccion que crea la solucion inicial
    
     private double tInicial = 1000;
    private double tMinima = 20;
    private double variableAlfa = 0;
    private double ratioEnfriamiento=0.003;
    private float alfaRecocido=1.0f;
    
     public Solucion crearSolucion(ArrayList<EmpleadoAlgoritmo> empleados, ArrayList<Galleta> arregloGalletas,Maquinas maquinas, double alfa){
        
        Solucion sol;
        Grasp algoritmoGrasp = new Grasp();
        sol=algoritmoGrasp.graspConstruccion(empleados,arregloGalletas,maquinas,1000,alfaRecocido);

     
        return sol;
        
    }
     
   public Solucion crearSolucion2(ArrayList<EmpleadoAlgoritmo> empleados, ArrayList<Galleta> arregloGalletas,Maquinas maquinas, int iteragrasp,double alfagrasp , int turno ){
        
        Solucion sol;
        Grasp algoritmoGrasp = new Grasp();
        sol=algoritmoGrasp.graspConstruccion2(empleados,arregloGalletas,maquinas,iteragrasp,alfagrasp,  turno);

      
        return sol;
        
    }

    
    public Solucion copiarSolucion(Solucion sol){
        Solucion nuevaSol = new Solucion();
        ArrayList<EmpleadoAlgoritmo> listaEmpleados = sol.getAsignados();
        ArrayList<EmpleadoAlgoritmo> nuevaLista = new ArrayList<EmpleadoAlgoritmo>();
        ArrayList<Galleta> listaGalletas = sol.getGalletas();
        ArrayList<Galleta> nuevaGalletas = new ArrayList<Galleta>();
        ArrayList<MaquinaA> listaMaquinas = sol.getMaquinas();
        ArrayList<MaquinaA> nuevaMaquinas = new ArrayList<MaquinaA >();
        EmpleadoAlgoritmo aux;
        Galleta auxGalleta;
        
        for (int i=0; i<listaEmpleados.size();i++){
            aux=copiarEmpleado(listaEmpleados.get(i));
            nuevaLista.add(aux);  
        }
        for (int i=0; i<listaGalletas.size();i++){
            auxGalleta=copiarGalleta(listaGalletas.get(i));
            nuevaGalletas.add(auxGalleta);
        }
         MaquinaA  maq = new MaquinaA ();
        for(int i=0;i<listaMaquinas.size()  ;i++){
           maq = listaMaquinas.get(i);
              MaquinaA   maquina = new MaquinaA(maq.getIdmaquina(), maq.getTipomaquina(), maq.getEstado());
              nuevaMaquinas.add(maquina);
        }
        
        nuevaSol.setAsignados(nuevaLista);
        nuevaSol.setGalletas(nuevaGalletas);
        nuevaSol.setMaquinas(nuevaMaquinas);
        nuevaSol.setFuncionObjetivo(sol.getFuncionObjetivo());
        
        return nuevaSol;      
    }
    
    public EmpleadoAlgoritmo copiarEmpleado(EmpleadoAlgoritmo emp){
        EmpleadoAlgoritmo nuevo=new EmpleadoAlgoritmo();
        Galleta nuevoGalleta;
        
        nuevo.setIdempleado(emp.getIdempleado());
        int[] prod = new int[4];
        int[] merm = new int[4];
        double[] efi = new double[4];
        
       // 
        for(int i =0 ;i< emp.getCapacidad().length; i++){
            prod[i] = emp.getProduccion()[i];
            merm[i] = emp.getMermas()[i];
            efi[i] = emp.getEficiencia()[i];
        }
        nuevo.setTipoMaquinaAsignada(emp.getTipoMaquinaAsignada());
        nuevo.setMaquina(emp.getMaquina());
        nuevoGalleta=copiarGalleta(emp.getGalletaAsignada());
        nuevo.setGalletaAsignada(nuevoGalleta);
        nuevo.calcularCap(nuevo.getProduccion(), nuevo.getMermas());
        nuevo.setTurno(emp.getTurno());
        return nuevo; 
    }
    

       public Galleta copiarGalleta(Galleta gall){
        Galleta nuevo=new Galleta();
        TipoGalleta nuevoTipo = new TipoGalleta();
        TipoGalleta tipoGalleta = gall.getTipogalleta();
        
        //seteando variables de tipoGalleta
        nuevoTipo.setIdTipo(tipoGalleta.getIdTipo());
        nuevoTipo.setCosto(tipoGalleta.getCosto());
        nuevoTipo.setPrecio(tipoGalleta.getPrecio());
        
        
        ArrayList<Integer> maquinasProceso = new ArrayList();
        ArrayList<Float> porcentajesValor = new ArrayList();
        ArrayList<Float> porcentajesCosto = new ArrayList();
        for(int i=0; i < tipoGalleta.getMaquinasProceso().size();i++){
            maquinasProceso.add(tipoGalleta.getMaquinasProceso().get(i));
            porcentajesValor.add(tipoGalleta.getPorcentajesValor().get(i));
            porcentajesCosto.add(tipoGalleta.getPorcentajesCosto().get(i));
        }
        nuevoTipo.setMaquinasProceso(maquinasProceso);
        nuevoTipo.setPorcentajesValor(porcentajesValor);
        nuevoTipo.setPorcentajesCosto(porcentajesCosto);
        //seteando variables de galleta
        nuevo.setIdgalleta(gall.getIdgalleta());
        nuevo.setNumGalletasPedidas(gall.getNumGalletasPedidas());
        nuevo.setDemandacubierta(gall.getDemandacubierta());
        nuevo.setTipogalleta(nuevoTipo);
        int[] maq_cub = new int[gall.getDemanda_maq_cubierta().length];
        int[] ini =  new int[gall.getDemanda_maq_cubierta().length];
         int[] maq_ped = new int[gall.getDemanda_maq_pedida().length];
         int[] ininuevo2 = new int[gall.getDemanda_maq_pedida().length];
        for(int i=0;i< maq_cub.length;i++) {
            maq_cub[i] = gall.getDemanda_maq_cubierta()[i];
            maq_ped[i]= gall.getDemanda_maq_pedida()[i];
            ini[i] = gall.getInv_ini_proc()[i];
            ininuevo2[1] = gall.getInv_nuevo()[i];
        }
        nuevo.setInv_ini_proc(ini);
        nuevo.setDemanda_maq_cubierta(maq_cub);
        nuevo.setdemanda_maq_pedida(maq_ped);
        nuevo.setInv_nuevo(ininuevo2);
        return nuevo;  
    }
        
        public Solucion recocido(Solucion solucionInicial,double fObjetivoInicial){
        
        double t=tInicial;
        double fobjetivoAux=0;
        double fobjetivo=fObjetivoInicial;
        Solucion solucion = solucionInicial;
        double metropolis;
        Random randomAux;
        double auxMetro;
        int cambioExitoso=0;
        int randomRuleta;
        Solucion solAux;
        int itera=0;
        int condicionParada=0;
        int i =0;
        int cambioMax;
        while(t>tMinima){
            itera++;
            Random r = new Random();
            randomRuleta=r.nextInt(2);
            solAux=copiarSolucion(solucion);
 
            i=i+1;
            cambioMax=0;
            while(cambioExitoso==0){
                cambioMax++;
                if (cambioMax>500) break;
                cambioExitoso = generarVecino(solAux);
                if (cambioExitoso == 1) {
                    solAux.calcularObjetivoTotal(Grasp.COSTOOPERACION);
                    fobjetivoAux = solAux.getFuncionObjetivo();
                
                    cambioExitoso = 0;
                    break;
                    
                }                
            }
            
            
            if (fobjetivoAux>0){
                               
                if (fobjetivoAux > fobjetivo) {
                    solucion = solAux;
                    fobjetivo = fobjetivoAux;
                    condicionParada=0;
                } else {
                    condicionParada++;
                    if (condicionParada>1000) {
                    break;
                    }

                    metropolis = Math.exp((((fobjetivoAux/1000) - (fobjetivo/1000)) / t));

                    metropolis = Math.exp((((fobjetivoAux) - (fobjetivo)) / t));
                    randomAux = new Random();
                    auxMetro=Math.random();
                    if (metropolis > auxMetro) {
                        solucion = solAux;
                        fobjetivo = fobjetivoAux;
                    }
                }
            } 
            
            //t=t*variableAlfa;
            t*=1-ratioEnfriamiento;
        }
        solucionInicial=solucion;
        fObjetivoInicial=fobjetivo;
     return solucion;
    }
        
    public Solucion recocido2(Solucion solucionInicial,double fObjetivoInicial,double tini, double ifin , double ratio){
        
        double t=tini;
        double fobjetivoAux=0;
        double fobjetivo=fObjetivoInicial;
        Solucion solucion = solucionInicial;
        double metropolis;
        Random randomAux;
        double auxMetro;
        int cambioExitoso=0;
        int randomRuleta;
        Solucion solAux;
        int itera=0;
        int condicionParada=0;
        int i =0;
        int cambioMax;
        while(t>ifin){
            itera++;
            Random r = new Random();
            randomRuleta=r.nextInt(2);
            solAux=copiarSolucion(solucion);
 
            i=i+1;
            cambioMax=0;
            while(cambioExitoso==0){
                cambioMax++;
                if (cambioMax>500) break;
                cambioExitoso = generarVecino(solAux);
                if (cambioExitoso == 1) {
                    solAux.calcularObjetivoTotal(Grasp.COSTOOPERACION);
                    fobjetivoAux = solAux.getFuncionObjetivo();
                
                    cambioExitoso = 0;
                    break;
                    
                }                
            }
            
            
            if (fobjetivoAux>0){
                               
                if (fobjetivoAux > fobjetivo) {
                    solucion = solAux;
                    fobjetivo = fobjetivoAux;
                    condicionParada=0;
                } else {
                    condicionParada++;
                    if (condicionParada>1000) {
                    break;
                    }

                    metropolis = Math.exp((((fobjetivoAux/1000) - (fobjetivo/1000)) / t));

                    metropolis = Math.exp((((fobjetivoAux) - (fobjetivo)) / t));
                    randomAux = new Random();
                    auxMetro=Math.random();
                    if (metropolis > auxMetro) {
                        solucion = solAux;
                        fobjetivo = fobjetivoAux;
                    }
                }
            } 
            
            //t=t*variableAlfa;
            t*=1-ratio;
        }
        solucionInicial=solucion;
        fObjetivoInicial=fobjetivo;
     return solucion;
    }
        
        public int generarVecino(Solucion sol){
        
         if(sol.getAsignados().size()>1) {  
        Random r = new Random();
        int indice1 = r.nextInt(sol.getAsignados().size());
        
        r = new Random();
        int indice2 = r.nextInt(sol.getAsignados().size());
        
        while(indice1==indice2){
            r = new Random();
            indice2 = r.nextInt(sol.getAsignados().size());
        }
         
        EmpleadoAlgoritmo emp1 = sol.getAsignados().get(indice1);
         int maquina1 = emp1.getTipoMaquinaAsignada();
         int idmaq = emp1.getMaquina();
         Galleta gal1 = emp1.getGalletaAsignada();

        EmpleadoAlgoritmo emp2 = sol.getAsignados().get(indice2);
        int maquina2 = emp2.getTipoMaquinaAsignada();
        int idmaq2 = emp2.getMaquina();
        Galleta gal2 = emp2.getGalletaAsignada();

        int w =0;
        int o=0;
        int posmaq1=0;
        int posmaq2=0;
        
        for(w =0;w< sol.getGalletas().size();w++ ){
          if( gal1.getIdgalleta()== sol.getGalletas().get(w).getIdgalleta()) break; //busco la posicion de la galleta en el arreglo
        }
        
        for(o=0;o< sol.getGalletas().size();o++){
            if(gal2.getIdgalleta()== sol.getGalletas().get(o).getIdgalleta()) break; 
        }
        
        for(posmaq1=0;posmaq1 < sol.getGalletas().get(w).getTipogalleta().getMaquinasProceso().size() ;posmaq1++){
            if(sol.getGalletas().get(w).getTipogalleta().getMaquinasProceso().get(posmaq1)== maquina1 )break;// busco la posicion del tipo de mauqina en el arreglo de maquinas de la galleta
        }
        
        for(posmaq2=0;posmaq2 < sol.getGalletas().get(o).getTipogalleta().getMaquinasProceso().size();posmaq2++){
            if(sol.getGalletas().get(o).getTipogalleta().getMaquinasProceso().get(posmaq2)== maquina2) break;
        }
        int cubierta_tipomaq1 = sol.getGalletas().get(w).getDemanda_maq_cubierta()[posmaq1];//obtengo la demanda cubierta en el tipo de maquina por esa galleta w
        int demanda = sol.getGalletas().get(w).getDemandacubierta();//obtengo la demanda q se debe cubrir
        
        
           
      //     int demanda = sol.getGalletas().get(w).getNumGalletasPedidas();
       
        int cubierta_tipomaq2 = sol.getGalletas().get(o).getDemanda_maq_cubierta()[posmaq2];
        int demanda2 = sol.getGalletas().get(o).getDemandacubierta();
     
        //  int demanda2 = sol.getGalletas().get(o).getNumGalletasPedidas();
        
//        if(cubierta_tipomaq1 -( emp1.getCapacidad()[maquina1-1] - 
//             emp2.getCapacidad()[maquina1-1])>= demanda && cubierta_tipomaq2
//              - (emp2.getCapacidad()[maquina2-1]- emp1.getCapacidad()[maquina2-1])>=demanda2)// verifico que en ambos cambios la demanda se siga cubriendo
        if(cubierta_tipomaq1 -( emp1.getCapacidad()[maquina1-1] - 
             emp2.getCapacidad()[maquina1-1])>= cubierta_tipomaq1 && cubierta_tipomaq2
              - (emp2.getCapacidad()[maquina2-1]- emp1.getCapacidad()[maquina2-1])>=cubierta_tipomaq2)
        {
            emp1.setTipoMaquinaAsignada(maquina2);
            emp1.setMaquina(idmaq2);
            emp1.setGalletaAsignada(gal2);
                        
            emp2.setTipoMaquinaAsignada(maquina1);
            emp2.setMaquina(idmaq);
            emp2.setGalletaAsignada(gal1);
                         
            int resta = ( emp1.getCapacidad()[maquina1-1]-  emp2.getCapacidad()[maquina1-1]);             
            int[]arr= sol.getGalletas().get(w).getDemanda_maq_cubierta();
           // arr[posmaq1] = cubierta_tipomaq1 - resta;
            sol.getGalletas().get(w).actualizaDemCub(posmaq1, cubierta_tipomaq1 - resta);
                    //.setDemanda_maq_cubierta(arr);
             
                  
            int resta2 = (emp2.getCapacidad()[maquina2-1]- emp1.getCapacidad()[maquina2-1]);    
            int[] arr2= sol.getGalletas().get(o).getDemanda_maq_cubierta();
           // arr2[posmaq2]=cubierta_tipomaq2 - resta2; 
            sol.getGalletas().get(o).actualizaDemCub(posmaq2, cubierta_tipomaq2 - resta2); //.setDemanda_maq_cubierta(arr2);
            
              
            if(maquina1 == 4){
               int[] arrmaquinas = sol.getGalletas().get(w).getDemanda_maq_cubierta();
               int tam = arrmaquinas.length;
               int dem =sol.getGalletas().get(w).getDemanda_maq_cubierta()[tam -1];
              // sol.getGalletas().get(w).calcularDemandacubierta(arrmaquinas);
           sol.getGalletas().get(w).calDemCubV2();
            }
              
           if(maquina2== 4){
               int[] arrmaquinas2 =sol.getGalletas().get(o).getDemanda_maq_cubierta();
               int tam2 = arrmaquinas2.length;
               int dem2 = sol.getGalletas().get(o).getDemanda_maq_cubierta()[tam2 -1];
              // sol.getGalletas().get(o).calcularDemandacubierta(arrmaquinas2);
         sol.getGalletas().get(o).calDemCubV2();
            }
           return 1;//se realizo intercambio
        }
       return 0;//no se genero vecino
         } return 0;   
    }
        
    public Solucion recocido_run(ArrayList<EmpleadoAlgoritmo> empleados, ArrayList<Galleta> galletas, Maquinas maquinas ){
         Solucion solInicial;
         solInicial = crearSolucion(empleados, galletas, maquinas, alfaRecocido);
         solInicial.calcularObjetivoTotal(Grasp.COSTOOPERACION);
         double  fObjetivo=solInicial.getFuncionObjetivo();  
         return recocido(solInicial,fObjetivo);
    }
     
     
    public Solucion recocido_run2(ArrayList<EmpleadoAlgoritmo> empleados, ArrayList<Galleta> galletas, Maquinas maquinas, int iteragrasp, double alfa,double tini, double ifin , double ratio, int turno) {
    Solucion solInicial;
       
        
         solInicial = crearSolucion2(empleados, galletas, maquinas, iteragrasp, alfa, turno);
         solInicial.calcularObjetivoTotal(Grasp.COSTOOPERACION);
         double  fObjetivo=solInicial.getFuncionObjetivo();  
         Solucion solucion = recocido2(solInicial,fObjetivo, tini, ifin , ratio);
         solucion.ordenarGall();
         return solucion;
    }       
}
